/**
 * - 作者: DoooReyn
 * - 日期: 2023.10.31
 */

import { sys } from 'cc';
import { Dictionary, Logger, Objects } from '../../../../wing/assets/src';
import { Manager } from './Manager';

/** 存储数据格式 */
type StoreData = Record<string, any>;

/** 存储功能 */
const store = sys.localStorage;

/**
 * 存储记录
 * - 注意：
 *   - 应该尽量保持数据的结构简单化
 *   - 不要嵌套太多层或使用复杂结构
 */
class StoreRecord<D extends StoreData> {
    /** 记录名称 */
    private __key: string;

    /** 记录模板 */
    private __data: D;

    /**
     * @param key 记录名称
     * @param data 记录模板
     */
    constructor(key: string, data: D) {
        this.__key = key;
        this.__data = Objects.cloneInLossy(data);
        this.parse();
    }

    /** 解析数据 */
    private parse() {
        let str = store.getItem(this.__key);
        if (str) {
            try {
                str = Array.prototype.map.call(str, (v, i) => String.fromCharCode(v.charCodeAt(0) - i - 0x77)).join('');
                const temp = JSON.parse(str) as D;
                for (let k in temp) {
                    if (this.__data[k] !== undefined) {
                        this.__data[k] = temp[k];
                    }
                }
            } catch (e) {
                Logger.getLogger('LocalStore').warn('解析存储项失败', this.__key, e);
            }
        }
        this.save();
    }

    /** 保存项目 */
    public save() {
        const str = JSON.stringify(this.__data);
        const ret = Array.prototype.map.call(str, (v, i) => String.fromCharCode(v.charCodeAt(0) + i + 0x77)).join('');
        store.setItem(this.__key, ret);
    }

    /**
     * 读取存储项
     * @param key 存储项键名
     * @returns
     */
    public read<K extends keyof D>(key: K): D[K] {
        return this.__data[key];
    }

    /**
     * 获取存储项值
     * @param key 存储项键名
     * @param value 存储项值
     */
    public write<K extends keyof D>(key: K, value: D[K]) {
        this.__data[key] = value;
        this.save();
    }

    /** 遍历 */
    public each(fn: (k: keyof D, v: D[keyof D]) => boolean) {
        for (let k in this.__data) {
            if (!fn(k, this.__data[k])) break;
        }
    }
}

/** 本地存储记录管理器 */
export class LocalStore extends Manager {
    /** 本地记录 */
    private __dict: Dictionary<StoreRecord<any>>;

    /** 项目名称 */
    private __project: string;

    /** 模块名称 */
    public get uname(): string {
        return 'LocalStore';
    }

    /** 记录前缀 */
    protected prefix(key: string) {
        return this.__project + '-' + key;
    }

    /** @param project 项目名称 */
    protected async onInit(project: string): Promise<void> {
        this.__project = project;
        this.__dict = new Dictionary();
    }

    protected async onDeinit(): Promise<void> {
        Logger.removeLogger('LocalStore');
    }

    /**
     * 挂载记录
     * @param key 记录名称
     * @param data 记录模板
     * @returns
     */
    public mount<D extends StoreData>(key: string, data: D): StoreRecord<D> {
        key = this.prefix(key);
        if (!this.__dict.has(key)) {
            return this.__dict.add(key, new StoreRecord(key, data));
        } else {
            return this.__dict.fetch(key) as StoreRecord<D>;
        }
    }

    /**
     * 移除记录
     * @param key 记录名称
     */
    public unmount(key: string): void {
        key = this.prefix(key);
        this.__dict.remove(key);
        store.removeItem(key);
    }

    /**
     * 获取记录
     * @param key 记录名称
     * @returns
     */
    public get<D extends StoreData>(key: string): StoreRecord<D> {
        return this.__dict.fetch(this.prefix(key)) as StoreRecord<D>;
    }
}
